using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Threading;
using System.Collections.Specialized;
using System.Net.Sockets;
using IPDataAnalyzer.Protocol;
using System.Text.RegularExpressions;
using System.IO;

namespace IPDataAnalyzer
{
    public partial class FormMain : Form
    {
        System.Threading.Thread Sniffer;
        System.Net.Sockets.Socket socket;
        const int packetBufferSize = 65536;
        byte[] PacketBuffer = new byte[packetBufferSize];
        NameValueCollection dnsCache = new NameValueCollection();
        IPAddress ipaddress;

        delegate void LogIt(string log);
        LogIt logIt;
        public FormMain()
        {
            InitializeComponent();
        }

        private void FormMain_Load(object sender, EventArgs e)
        {
            resolveIP();
            logIt = new LogIt(Log2Listbox);
        }

        private void Log2Listbox(string log)
        {
            listBoxResult.Items.Insert(0, log);
        }

        private void invokeLogFormThread(string log)
        {
            this.Invoke(logIt, log);
        }

        private void resolveIP()
        {
            IPHostEntry hostEntry = Dns.GetHostEntry(Dns.GetHostName());
            if (hostEntry.AddressList.Length > 0)
            {
                for (int i = 0; i < hostEntry.AddressList.Length; i++)
                {
                    comboBoxIpAddress.Items.Add(hostEntry.AddressList[i].ToString());
                }
            }
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {
            if (comboBoxIpAddress.Text == "")
            {
                MessageBox.Show("Please select an IP!");
                return;
            }
            else
            {
                ipaddress = IPAddress.Parse(comboBoxIpAddress.Text);
            }
            buttonStart.Enabled = false;
            buttonStop.Enabled = true;
            Sniffer = new Thread(new ThreadStart(RunReceiver));
            Sniffer.Start();
        }

        private void RunReceiver()
        {
            try
            {
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
            }
            catch (System.Threading.ThreadAbortException)
            { }

            try
            {
                socket.Bind(new IPEndPoint(ipaddress, 0));
                socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, 1);
                socket.IOControl(unchecked((int)0x98000001), new byte[4] { 1, 0, 0, 0 }, new byte[4]);
                while (buttonStop.Enabled)
                {
                    IAsyncResult ar = socket.BeginReceive(PacketBuffer, 0, packetBufferSize, SocketFlags.None, new AsyncCallback(CallReceive), this);
                    while (socket.Available == 0)
                    {
                        Thread.Sleep(1);
                        if (buttonStop.Enabled == false)
                        {
                            break;
                        }
                    }
                    if (buttonStop.Enabled == false)
                    {
                        break;
                    }
                    int Size = socket.EndReceive(ar);
                    if (checkBoxLooseQueue.Checked == false)
                    {
                        ExtractBuffer();
                    }
                }
            }
            finally
            {
                if (socket != null)
                {
                    socket.Shutdown(SocketShutdown.Both);
                    socket.Close();
                }
            }
        }

        public virtual void CallReceive(IAsyncResult ar)
        {
            if (checkBoxLooseQueue.Checked) ExtractBuffer();
        }


        protected void ExtractBuffer()
        {
            IPPacket IP = new IPPacket(ref PacketBuffer);

            string SourceAddress = IP.SourceAddress.ToString();
            string DestinationAddress = IP.DestinationAddress.ToString();

            if (checkBoxResolveHostName.Checked)
            {
                string HostName = dnsCache[SourceAddress];
                if (HostName == null)
                {
                    dnsCache[SourceAddress] = "";

                    try
                    {
                        HostName = Dns.GetHostEntry(SourceAddress).HostName;
                    }
                    catch
                    {
                        HostName = "";
                    }

                    dnsCache[SourceAddress] = HostName;
                }
                if (HostName != SourceAddress) SourceAddress += " " + HostName;
                HostName = dnsCache[DestinationAddress];
                if (HostName == null)
                {
                    dnsCache[DestinationAddress] = "";

                    try
                    {
                        HostName = Dns.GetHostEntry(SourceAddress).HostName;
                    }
                    catch
                    {
                        HostName = "";
                    }

                    dnsCache[DestinationAddress] = HostName;
                }
                if (HostName != DestinationAddress) DestinationAddress += " " + HostName;
            }

            if (IP.TCP != null)
            {
                string Data = Regex.Replace(Encoding.ASCII.GetString(IP.TCP.PacketData), @"[^a-zA-Z_0-9\.\@\- ]", "");

                //listBoxResult.Items.Insert(0, "TCP " + SourceAddress + ":" + IP.TCP.SourcePort + " --> " + DestinationAddress + ":" + IP.TCP.DestinationPort + " " + Data);
                invokeLogFormThread("TCP " + SourceAddress + ":" + IP.TCP.SourcePort + " --> " + DestinationAddress + ":" + IP.TCP.DestinationPort + " " + Data);

            }
            else
                if (IP.UDP != null)
                {
                    string Data = Regex.Replace(Encoding.ASCII.GetString(IP.UDP.PacketData), @"[^a-zA-Z_0-9\.\@\- ]", "");

                    invokeLogFormThread("UDP " + SourceAddress + ":" + IP.UDP.SourcePort + " --> " + DestinationAddress + ":" + IP.UDP.DestinationPort + " " + Data);

                }
                else
                    if (IP.ICMP != null)
                    {
                        string Data = Regex.Replace(Encoding.ASCII.GetString(IP.ICMP.PacketData), @"[^a-zA-Z_0-9\.\@\- ]", "");

                        invokeLogFormThread("ICMP " + SourceAddress + " --> " + DestinationAddress + " " + IP.ICMP.Message + " " + Data);

                    }
                    else
                        invokeLogFormThread(IP.Protocol + " " + SourceAddress + " --> " + DestinationAddress);
        }

        private void buttonSave_Click(object sender, EventArgs e)
        {
            using (StreamWriter sw = new StreamWriter(System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) + "\\iplog.txt"))
            {
                for (int i = 0; i < listBoxResult.Items.Count; i++) sw.WriteLine(DateTime.Now + " " + listBoxResult.Items[i].ToString());
            }
        }

        private void buttonClear_Click(object sender, EventArgs e)
        {
            listBoxResult.Items.Clear();
        }

        private void buttonStop_Click(object sender, EventArgs e)
        {
            buttonStart.Enabled = true;
            buttonStop.Enabled = false;
        }

        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            System.Environment.Exit(0);
        }


    }
}